package basics.reflect;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理的实现
 * 需求：外面的人想要大明星唱一首歌
 * 1.获取代理的对象：代理对象 = Proxy.createProxyInstance(大明星对象)
 * 2.在调用代理的唱歌方法: 代理对象.唱歌方法()
 * 实现逻辑：
 * 1. 创建一个代理接口作为代理对象
 * 2. 创建一个需要被代理的对象实现代理接口
 * 3. 创建一个创建代理对象的方法（Proxy.newProxyInstance(),
 * 第一个参数是类加载器，代理对象数组类,invoctionHanlder匿名实现方法，
 * 在invoke里面处理逻辑，最后返回method.invoke(被代理对象,args)），
 * 4.调用代理对象执行被代理对象的方法
 *
 * @author chenzhihua
 * @Date 2024/7/12
 */
public class DynamicProxyTest {
    public static void main(String[] args) {
        // 1. 获取代理对象
        BigStar bigStar = new BigStar("鸡哥");
        Star star = createStar(bigStar);

        star.sing("鸡你太美");
    }


    /**
     * 方法的作用：给一个明星对象创建一个代理
     * 形参：被代理的明星对象
     * 返回值：给明星创建的代理
     *
     * @param bigStar
     * @return
     */
    public static Star createStar(BigStar bigStar) {
        // 形参1：用于指定那个类加载器，去加载生成的代理类
        // 形参2：指定接口，这些接口用于指定生成的代理长什么样，有那些方法
        // 形参3：指定生成的代理对象要干什么事情
        Star star = (Star) Proxy.newProxyInstance(
                DynamicProxyTest.class.getClassLoader(),
                new Class[]{Star.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /**
                         * 参数一： proxy：代理的对象
                         * 参数二： method：要运行的方法
                         * 参数三： args：调用运行的方法的参数
                         */
                        if ("sing".equals(method.getName())) {
                            System.out.println("准备话筒，收钱");
                        } else if ("dance".equals(method.getName())) {
                            System.out.println("准备场地，收钱");
                        }
                        // 找大明星开始唱歌或者跳舞（被代理对象执行方法）
                        return method.invoke(bigStar, args);
                    }
                });
        return star;
    }
}


// 实际对象
class BigStar implements Star {
    private String name;

    @Override
    public String sing(String name) {
        System.out.println(this.name + "在唱" + name);
        return "谢谢大家的支持";
    }

    @Override
    public void dance(String name) {
        System.out.println(this.name + "在跳" + name);
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigStar() {
    }

    public BigStar(String name) {
        this.name = name;
    }
}


// 代理对象
interface Star {

    String sing(String name);

    void dance(String name);
}